/**
* Copyright (c) By zengqh.
*
* This program is just for fun or demo, in the hope that it  
* will be useful, you can redistribute it and/or modify freely.
*
* Time: 2012/07/11
* File: OGLTexture2D.cpp
* Blog: http://www.cnblogs.com/zengqh/
**/

#include "OGLTexture2D.h"

#define FREEIMAGE_BIGENDIAN

#include "../../FreeImage/FreeImage.h"

OGLTexture2D::OGLTexture2D()
: _handle(0)
, _width(0), _height(0)
{
	_is_mipmap = false;
}

OGLTexture2D::OGLTexture2D(const std::string& path, bool is_mipmap)
: Texture(path, is_mipmap)
, _handle(0)
, _width(0), _height(0)
{
	createTexture();
}

OGLTexture2D::~OGLTexture2D()
{

}

bool OGLTexture2D::createTexture()
{
	FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
	FIBITMAP* dib = NULL;
	u8* bits = NULL;
	s32 width, height;
	s32 bpp;
	GLint internal_format, format;
	GLenum type;
	u32 src_pitch;

	fif = FreeImage_GetFileType(_path.c_str(), 0);
	if (fif == FIF_UNKNOWN) return false;

	dib = FreeImage_Load(fif, _path.c_str());

	bits = FreeImage_GetBits(dib);
	width = FreeImage_GetWidth(dib);
	height = FreeImage_GetHeight(dib);
	bpp = FreeImage_GetBPP(dib);
	src_pitch = FreeImage_GetPitch(dib);

	if (!bits || width == 0 || height == 0 || bpp <= 0) return false;

	if (bpp == 8)		
	{
		_texture_type = TT_8_BITS;
		format = GL_BGR;
		internal_format = 1;
		type = GL_UNSIGNED_BYTE;
	}
	else if (bpp == 16)	
	{
		_texture_type =  TT_16_BITS;
		format = GL_BGR;
		internal_format = 2;
		type = GL_UNSIGNED_SHORT_5_6_5;
	}
	else if (bpp == 24)	
	{
		_texture_type = TT_24_BITS;
		format = GL_RGB;
		internal_format = 3;
		type = GL_UNSIGNED_BYTE;
	}
	else if (bpp == 32)	
	{
		_texture_type = TT_32_BITS;
		format = GL_RGBA;
		internal_format = 4;
		type = GL_UNSIGNED_BYTE;
	}
	else
	{
		rf_assert(0);
	}

	rf_assert(_handle == 0);

	if (_is_mipmap)
	{
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}
	else
	{
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}

	glGenTextures(1, &_handle);

	glBindTexture(GL_TEXTURE_2D, _handle);
	glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, type, bits);

	if (_is_mipmap)
	{
		glGenerateMipmap(GL_TEXTURE_2D);
	}

	glBindTexture(GL_TEXTURE_2D, 0);

	FreeImage_Unload(dib);

	_width = width;
	_height = height;
}

bool OGLTexture2D::destroyTexture()
{
	if (_handle)
	{
		glDeleteTextures(1, &_handle);

		return true;
	}

	return false;
}

void OGLTexture2D::setPath(const std::string& path)
{
	_path = path;
}

void OGLTexture2D::setMipmap(bool is_mipmap)
{
	_is_mipmap = is_mipmap;
}

const std::string& OGLTexture2D::getPath() const
{
	return _path;
}

bool OGLTexture2D::isMipmap() const
{
	return _is_mipmap;
}

TextureType OGLTexture2D::getTextureType() const
{
	return _texture_type;
}

bool OGLTexture2D::saveTexture(const std::string& path)
{
	u8* texture_buffer = new u8[_width * _height * 32];

	glBindTexture(GL_TEXTURE_2D, _handle);

	glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_buffer);

	FIBITMAP* bitmap = FreeImage_Allocate(_width, _height, 32);
	RGBQUAD color;

	for(int y = 0; y < _height; ++y)
	{
		for(int x = 0; x < _width; ++x)
		{
			unsigned char* curr = (unsigned char*)texture_buffer + y * _width * 4 + x * 4;
			color.rgbRed = curr[2];
			color.rgbGreen = curr[1];
			color.rgbBlue = curr[0];
			color.rgbReserved = curr[3];

			FreeImage_SetPixelColor(bitmap, x, y, &color);
		}
	}

	FREE_IMAGE_FORMAT format = FIF_PNG;
	FreeImage_Save(format, bitmap, path.c_str());

	FreeImage_Unload(bitmap);

	safe_delete_array(texture_buffer);

	return true;
}

s32 OGLTexture2D::getTextureWidth() const
{
	return _width;
}

s32 OGLTexture2D::getTextureHeight() const
{
	return _height;
}

GLuint OGLTexture2D::getTextureID() const
{
	return _handle;
}

void OGLTexture2D::active(s32 index)
{
	glActiveTexture(GL_TEXTURE0 + index);
	glBindTexture(GL_TEXTURE_2D, _handle);
}